const hx = require('hbuilderx')
const { join } = require('path/posix')
const { format } = require('util')
const fs = require('fs-extra')
const theme = require('./src/utils/theme.js')
const log = require('./src/utils/log.js')
const { connections, views, constant, clients, disposables } = require('./src/utils/cache.js')
const viewManager = require('./src/utils/view-manager.js')
const connection = require('./src/utils/connection.js')
const progress = require('./src/utils/progress.js')
const { forIn } = require('lodash')

function registerCommand(context, id, fn) {
    let disposable = hx.commands.registerCommand(id, fn)
    context.subscriptions.push(disposable)
}

function init(context) {
    registerCommand(context, 'extension.openExplorer', () => {
        viewManager.open('create-connection')
    })
}

function onSaveDocument(context) {
    const disposable = hx.workspace.onDidSaveTextDocument(async function (document) {
        const source = join(document.uri.fsPath + '.source')
        if (!(await fs.pathExists(source))) {
            return
        }
        const sourceOptions = await fs.readJson(source)
        let client = connections.get(sourceOptions.host)
        if (!client) {
            const options = await clients.findOne({ host: sourceOptions.host })
            if (!options) {
                const msg = format('[%s] 服务器没有录入, 同步失败。', sourceOptions.host)
                return log.statusBarErr(msg)
            }
            if (sourceOptions.isNotConfirmConnect) {
                const msg = format('[%s] 未连接到服务器, 同步失败。', sourceOptions.host)
                return log.statusBarErr(msg)
            }
            let btn = await hx.window.showMessageBox({
                type: 'question',
                title: '连接服务器?',
                text: '即将连接到服务器 - ' + sourceOptions.host,
                buttons: ['不在询问', '确定', '取消']
            })
            if (btn == '确定') {
                try {
                    client = await connection.connect(options)
                } catch (error) {
                    const msg = format(
                        '[%s] 连接服务器失败, 同步失败, %s',
                        sourceOptions.host,
                        error.message || '未知错误'
                    )
                    return log.notice.error(msg)
                }
            } else {
                if (btn == '不在询问') {
                    sourceOptions.isNotConfirmConnect = true
                    await fs.writeJson(document.uri.fsPath + '.source', sourceOptions)
                }
                const msg = format('[%s] 未连接到服务器, 同步失败。', sourceOptions.host)
                return log.statusBarErr(msg)
            }
        }
        const serverStat = await client.connection.stat(sourceOptions.serverPath)
        const override = async () => {
            let msg = format('正在向 [%s] 服务器同步修改...', sourceOptions.host)
            hx.window.setStatusBarMessage(msg, 10000, 'info')
            const logs = progress.Upload.File()
            await client.connection.uploadFile(
                document.uri.fsPath,
                sourceOptions.serverPath,
                logs.onProgress,
                true
            )
            const clientStat = await fs.stat(document.uri.fsPath)
            sourceOptions.mtime = Math.floor(clientStat.mtimeMs / 1000)
            sourceOptions.size = clientStat.size
            const atime = Math.floor(clientStat.atimeMs / 1000)
            await client.connection.utimes(sourceOptions.serverPath, atime, sourceOptions.mtime)
            await fs.writeJson(document.uri.fsPath + '.source', sourceOptions)
            msg = format('修改已经同步到[%s]服务器。', sourceOptions.host)
            hx.window.setStatusBarMessage(msg, 5000, 'info')
        }
        if (serverStat.mtime <= sourceOptions.mtime) {
            await override()
        } else {
            const button = await hx.window.showMessageBox({
                type: 'question',
                title: '同步确认',
                text: '服务器上文件有最新的修改, 请选择操作?',
                buttons: ['覆盖', '拉取', '取消']
            })
            if (button == '覆盖') {
                await override()
            } else if (button == '拉取') {
                await client.connection.downloadFile(document.uri.fsPath, sourceOptions.serverPath)
                const msg = format('服务器 %s 上的修改已拉取到本地。', sourceOptions.host)
                const stat = await client.connection.stat(sourceOptions.serverPath)
                sourceOptions.mtime = stat.mtime
                sourceOptions.size = stat.size
                await fs.writeJson(document.uri.fsPath + '.source', sourceOptions)
                hx.window.setStatusBarMessage(msg, 5000, 'info')
            }
        }
    })
    context.subscriptions.push(disposable)
}

function onConfiguationChange(context) {
    let disposable = hx.workspace.onDidChangeConfiguration(function (event) {
        if (
            event.affectsConfiguration('editor.colorScheme') ||
            event.affectsConfiguration('editor.fontSize') ||
            event.affectsConfiguration('editor.fontFamily')
        ) {
            const value = theme.getHBuilderXThemeData('siderBar')
            forIn(views, view => {
                view?.onFn('setTheme', value)
            })
        }
    })
    context.subscriptions.push(disposable)
}

function onDocumentChange(context) {
    let disposable = hx.workspace.onDidChangeTextDocument(async function (event) {
        if (event.contentChanges.length != 1) {
            return
        }
        const change = event.contentChanges.at(0)
        const { range, text } = change
        const { start, end } = range
        const startLine = start.line
        const endLine = end.line
        if (startLine != endLine) {
            return
        }
        const line = event.document.lineAt(startLine)
        if (!line.text.startsWith(':>') || text != '\r\n') {
            return
        }
        if (connections.size == 0) {
            return
        }
        const tip = format('请选择执行该命令[%s]的目标服务器。', line.text)
        let host = await hx.window.showMessageBox({
            type: 'question',
            title: '是否执行该命令?',
            text: tip,
            buttons: [...connections.keys(), '取消']
        })
        if (host != '取消') {
            const client = connections.get(host)
            const output = await client.connection.execute(line.text.substring(2))
            log.info(output + '\n\n')
        }
    })
    context.subscriptions.push(disposable)
}

function onUrl(context) {
    let disposable = hx.window.registerUriHandler(
        {
            handleUri: async function (uri) {
                const params = new URLSearchParams(uri.query)
                const host = params.get('host')
                const path = params.get('path')
                if (uri.path.endsWith('/create-connection')) {
                    const options = await clients.findOne({ host: host })
                    if (!options) {
                        return log.notice.error('此服务器没有录入')
                    }
                    const client = connections.get(host)
                    if (!client) {
                        return await connection.connect(options)
                    }
                    const contentId = views?.['server-explorer']?.contentId
                    if (contentId != host) {
                        viewManager.open('server-explorer', host, options)
                    }
                } else if (uri.path.endsWith('/upload')) {
                    const options = await clients.findOne({ host: host })
                    if (!options) {
                        return log.notice.error('此服务器没有录入')
                    }
                    const client = connections.get(host) || (await connection.connect(options))
                    const serverPath = await hx.window.showInputBox({
                        prompt: '请输入服务器路径',
                        password: false
                    })
                    const stat = await fs.stat(path)
                    const logs = stat.isDirectory()
                        ? progress.Upload.Path()
                        : progress.Upload.File()
                    await client.connection.upload(path, serverPath, logs.onProgress, true)
                    logs.showDetail()
                }
            }
        },
        context
    )
    context.subscriptions.push(disposable)
}

function activate(context) {
    constant.setContext(context)
    init(context)
    onSaveDocument(context)
    onConfiguationChange(context)
    onDocumentChange(context)
    onUrl(context)
    const statusBar = hx.window.createStatusBarItem(hx.StatusBarAlignment.Right, 100)
    statusBar.text = '服务器'
    statusBar.command = 'extension.openExplorer'
    statusBar.tooltip = '管理服务器文件'
    statusBar.show()
    disposables.push(() => statusBar.dispose())
}

function deactivate() {
    disposables.forEach(fn => {
        try {
            fn()
        } catch (error) {
            console.log(error)
        }
    })
    connections.forEach(value => {
        try {
            connection.disconnect(value.host, false)
        } catch (error) {
            console.log(error)
        }
    })
    hx.window.clearStatusBarMessage()
}

module.exports = {
    activate,
    deactivate
}
